import Data from "../object/Data"
import ObservableValue, { createObVal } from "../observer/observable.value"
import o from "../math/51263"
import ObservableMap from "../observer/observable.map"

import toolEnum from "../enum/tool.enum"
import SweepState from "../object/SweepState"
import SweepData from "../data/SweepData"
import sweepPlacementEnum from "../enum/sweepPlacement.enum"
import Sweep from "../object/Sweep"

interface derivedItem {
  id: string
  floorId: string
  position: any
  index: number
  alignmentType: string
  dataIndex: number
  placed: boolean
  enabled: boolean
  name: string
}

export default class SweepViewData extends Data {
  data: SweepData
  states: ObservableMap<SweepState>
  toolStateObservable: ObservableValue<string>
  derivedData: Record<string, derivedItem>
  selectedSweepObservable: ObservableValue<any>
  constructor(data: SweepData) {
    super()
    this.data = data
    this.name = "sweeps-view"
    this.states = new ObservableMap()
    this.toolStateObservable = createObVal(toolEnum.CLOSED)
    this.derivedData = {}
    this.selectedSweepObservable = new ObservableValue(null)
    const t = [toolEnum.MOVING, toolEnum.PLACING, toolEnum.PRESSING, toolEnum.ROTATING]
    data.makeSweepChangeSubscription(() => {
      t.includes(this.toolState) || this.selectCurrentSweep()
    })
    data.iterate(e => {
      const t = new SweepState()
      this.states.set(e.id, t)
      t.commit()
    })
    this.updateViewData()
  }
  selectCurrentSweep() {
    this.setSelectedSweep(this.data.currentSweep || null)
  }
  sweepVisibilityRule(e: Sweep) {
    return this.defaultSweepVisibilityRule(e)
  }
  defaultSweepVisibilityRule(e: Sweep) {
    return e.enabled
  }
  updateViewData() {
    this.data.iterate((e, t) => {
      this.derivedData[e.id] = this.makeViewDataForSweep(e, t)
    })
    this.commit()
  }
  updateSweepVisibilityRule(e) {
    this.sweepVisibilityRule = e || this.defaultSweepVisibilityRule
  }
  getSweepVisibility(e: Sweep) {
    return this.sweepVisibilityRule(e)
  }
  get selectedSweep() {
    return this.selectedSweepObservable.value
  }
  setSelectedSweep(e) {
    if (e === this.selectedSweep) return
    const t = this.selectedSweep
    if (((this.selectedSweepObservable.value = e), null !== e)) {
      const t = this.getState(e)
      t.selected = !0
      t.commit()
    }
    if (null !== t) {
      const e = this.getState(t)
      e.selected = !1
      e.commit()
    }
  }
  onSelectedSweepChanged(e) {
    return this.selectedSweepObservable.onChanged(e)
  }
  setToolState(e) {
    e === toolEnum.PLACING && this.selectedSweep && this.setSelectedSweep(null), (this.toolStateObservable.value = e)
  }
  get toolState() {
    return this.toolStateObservable.value
  }
  onToolStateChanged(e) {
    return this.toolStateObservable.onChanged(e)
  }
  getSweep(e) {
    return this.data.getSweep(e)
  }
  makeViewDataForSweep(e: Sweep, t: number) {
    const i = this.derivedData[e.id]
    return i
      ? ((i.floorId = e.floorId),
        (i.position = e.position),
        (i.alignmentType = e.alignmentType),
        (i.placed = e.placementType === sweepPlacementEnum.MANUAL),
        (i.enabled = e.enabled),
        (i.name = e.name),
        i)
      : {
          id: e.id,
          floorId: e.floorId,
          position: e.position,
          index: e.index,
          alignmentType: e.alignmentType,
          dataIndex: t,
          placed: e.placementType === sweepPlacementEnum.MANUAL,
          enabled: e.enabled,
          name: e.name
        }
  }
  getViewData(e: string) {
    const t = this.data.getSweep(e)
    const i = this.derivedData[e]
    t && !i && (this.derivedData[e] = this.makeViewDataForSweep(t, t.index))
    return this.derivedData[e]
  }
  isSweepAligned(e: string) {
    return this.data.isSweepAligned(e)
  }
  iterate(e: (v: Sweep, i?: number) => void) {
    this.data.iterate(e)
  }
  getState(e: string) {
    return this.states.get(e)
  }
  isVisible(e: string) {
    return this.states.get(e).visible
  }
  setVisible(e: string, visible) {
    const i = this.getState(e)
    i.visible !== visible && ((i.visible = visible), i.commit())
  }
  updateAnimations(e) {
    for (const t of this.states) t.animation.tick(e)
  }
  modifySelectAnimation(e: string, t, i) {
    const n = this.getState(e).animation,
      s = 1 === n.endValue
    t !== s && (s ? n.modifyAnimation(n.value, 0, i) : n.modifyAnimation(0, 1, i))
  }
  getIndexByAlignment(ALIGNED: boolean, id: string) {
    return this.getAlignedSweeps(ALIGNED).findIndex(e => e.id === id)
  }
  getAlignedSweeps(ALIGNED: boolean) {
    const t = Object.values(this.derivedData)
    return ALIGNED ? t.filter(o._T()) : t.filter(o.WO())
  }
}
